#include <iostream>
#include <filesystem>
#include <fstream>
#include "json.hpp"
#include <execution>
#include <vector>
using json = nlohmann::json;

std::vector<int> concatenateVectors(std::vector<int>&& vec1, const std::vector<int>& vec2)
{
    vec1.insert(vec1.end(), vec2.begin(), vec2.end());
    return vec1;
}

std::vector<int> deserializeJsonFile(const std::filesystem::path& filePath)
{
    std::ifstream file(filePath);
    if (!file.is_open())
    {
        std::cerr << "open fail" << filePath << std::endl;
        return {};
    }
    json j;
    file >> j;
    return j.get<std::vector<int>>();
}

void do_work(int offset, std::vector<int>& v)
{
    std::transform(
        std::execution::par_unseq,
        v.begin(),
        v.end(),
        v.begin(),
        [offset,v](int num)
        {
            return (num != -1) ? num + offset * 6400 : -1;
        }
    );
}

std::vector<int> deserializeJsonFile(const std::filesystem::path& filePath, int offset, bool flag)
{
    std::vector<int> v;
    std::ifstream file(filePath);
    if (!file.is_open())
    {
        std::cerr << "open fail" << filePath << std::endl;
        return {};
    }
    json j;
    file >> j;
    if (flag)
    {
        auto x = j[filePath.stem().string()].get<std::vector<std::vector<int>>>();
        v = x[1];
    }
    else
    {
        v = j[filePath.stem().string()].get<std::vector<int>>();
    }
    do_work(offset, v);
    return v;
}

struct Back
{
    std::vector<int> rtMissed;
    std::vector<int> rtmMissed;
    std::multimap<int, int> rtDeviation;
};

Back checkRT(const std::vector<int>& rt, const std::vector<int>& rtr)
{
    Back back;
    if (rt.empty() || rtr.empty())
    {
        return back;
    }

    int maxOffset = abs(rt[1] - rt[0]) / 2;
    int indexForRtr = 0;
    int indexForRt = 0;
    bool flag = false;

    while (indexForRt < rt.size() && indexForRtr < rtr.size())
    {
        int deviation = abs(rt[indexForRt] - rtr[indexForRtr]);
        if (deviation < maxOffset)
        {
            back.rtDeviation.insert((std::pair<int, int>(deviation, rt[indexForRt])));
            indexForRtr++;
            flag = true;
        }
        else
        {
            if (!flag)
            {
                back.rtMissed.push_back(rt[indexForRt]);
            }
            flag = false;
            indexForRt++;
        }
    }

    while (indexForRt < rt.size())
    {
        back.rtMissed.push_back(rt[indexForRt]);
        indexForRt++;
    }

    return back;
}
void checkRes(const std::vector<int>& rt, const std::vector<int>& rtr,const std::filesystem::directory_entry &entry,std::string name) {
    Back back;
    if (rt.size() < 2 || rtr.empty()) {
        return;
    }
    int maxOffset = std::abs(rt[1] - rt[0]) / 2;
    size_t indexForRtr = 0;
    for (size_t indexForRt = 0; indexForRt < rt.size(); ++indexForRt) {
        bool matched = false;
        while (indexForRtr < rtr.size()) {
            int deviation = std::abs(rt[indexForRt] - rtr[indexForRtr]);
            if (deviation < maxOffset) {
                back.rtDeviation.insert((std::pair<int, int>(deviation, rt[indexForRt])));
                ++indexForRtr;
                matched = true;
                break;
            } else if (rtr[indexForRtr] > rt[indexForRt]) {
                break;
            } else {
                back.rtmMissed.push_back(rtr[indexForRtr]);
                ++indexForRtr;
            }
        }
        if (!matched) {
            back.rtMissed.push_back(rt[indexForRt]);
        }
    }
    for(int i = indexForRtr; i < rtr.size(); ++i)
                {
                    back.rtmMissed.push_back(rtr[i]);
                }
    std::ofstream report_file(entry.path() / (name+"report.txt"));
        if (report_file.is_open())
        {
            report_file << "Report for directory: " << entry.path().filename() << std::endl;
            report_file << "matlab" << rt.size() << std::endl;
            report_file << "dec" << rtr.size() << std::endl;
            report_file << "sumR deviation   " << static_cast<int>(rt.size()) - static_cast<int>(rtr.size()) <<std::endl;
            report_file << "dec more    "<<back.rtmMissed.size()<<std::endl;
            for(auto& item : back.rtmMissed)
            {
                report_file << item << "  ";
            }
            report_file << std::endl;
            report_file << "dec miss" <<"    "<< back.rtMissed.size() << std::endl;
            for (auto& item : back.rtMissed)
            {
                report_file << item << "  ";
            }
            report_file << std::endl;
            report_file << "deviation   " << back.rtDeviation.size() << std::endl;
            for (int i = 0; i < 50; i++)
            {
                auto it = back.rtDeviation.equal_range(i);
                int count = std::distance(it.first, it.second);
                if(count==0)
                {
                    continue;
                }
                report_file <<"本组小计"<<count << "个差距为" << i << "     " << static_cast<double>(count) / rtr.size() * 100 <<
                    "%"
                    << std::endl;
                for (auto it2 = it.first; it2 != it.second; ++it2)
                {
                    report_file << it2->second << "  ";
                }
                report_file << std::endl;
            }
            report_file << "差距大于" << 10 << ":" << std::endl;
            int count = 0;
            for (const auto& pair : back.rtDeviation)
            {
                if (pair.first > 10)
                {
                    report_file << pair.second << "  "<<pair.first << std::endl;
                    count++;
                }
            }
            report_file <<"本组小计"<< count << " 差距大于标定" <<std::endl<<(double)count / rtr.size() * 100 << "%" <<
                std::endl;
            report_file.close();
        }
        else
        {
            std::cerr << "Failed to create report file for directory: " << entry.path().filename() << std::endl;
        }
}

int main()
{
    std::filesystem::path project_path = ".";
    std::filesystem::path folder_name = "DATA";
    std::filesystem::path target_folder = project_path / folder_name;
    if (!std::filesystem::exists(target_folder))
    {
        std::cout << "file is not exist" << std::endl;
        return 0;
    }
    for (const auto& entry : std::filesystem::directory_iterator(target_folder))
    {
        if (!entry.is_directory())
        {
            continue;
        }
        std::vector<int> RC;
        std::vector<int> TC;
        std::vector<int> PeaksC;
        std::vector<int> NotchC;
        std::vector<int> RM;
        std::vector<int> TM;
        std::vector<int> PeaksM;
        std::vector<int> NotchM;
        int offset = 0;
        int offset2 = 0;
        int offset3 = 0;
        int offset4 = 0;
        for (const auto& sub_entry : std::filesystem::directory_iterator(entry.path()))
        {
            if (sub_entry.path().extension() == ".json")
            {
                if (sub_entry.path().filename() == "local_R.json")
                {
                    RM = deserializeJsonFile(sub_entry.path());
                }
                else if (sub_entry.path().filename() == "local_T.json")
                {
                    TM = deserializeJsonFile(sub_entry.path());
                }
                else if (sub_entry.path().filename() == "local_Notch.json")
                {
                    NotchM = deserializeJsonFile(sub_entry.path());
                }
                else if (sub_entry.path().filename() == "local_peaks.json")
                {
                    PeaksM = deserializeJsonFile(sub_entry.path());
                }
            }
            if (sub_entry.is_directory())
            {
                for (const auto& sub_sub_entry : std::filesystem::directory_iterator(sub_entry.path()))
                {
                    if (sub_sub_entry.path().filename() == "R_DetectedByComputer.txt")
                    {
                        RC = concatenateVectors(std::move(RC),
                                                deserializeJsonFile(sub_sub_entry.path(), offset, true));
                        offset++;
                    }
                    else if (sub_sub_entry.path().filename() == "T_DetectedByComputer.txt")
                    {
                        TC = concatenateVectors(std::move(TC),
                                                deserializeJsonFile(sub_sub_entry.path(), offset2, true));
                        offset2++;
                    }
                    else if (sub_sub_entry.path().filename() == "PeakPoint.txt")
                    {
                        PeaksC = concatenateVectors(std::move(PeaksC),
                                                    deserializeJsonFile(sub_sub_entry.path(), offset3, false));
                        offset3++;
                    }
                    else if (sub_sub_entry.path().filename() == "DicroticNotch.txt")
                    {
                        NotchC = concatenateVectors(std::move(NotchC),
                                                    deserializeJsonFile(sub_sub_entry.path(), offset4, false));
                        offset4++;
                    }
                }
            }
        }
        checkRes(RM, RC,entry,"R");
        checkRes(TM, TC,entry,"T");
        checkRes(PeaksM, PeaksC,entry,"Peaks");
        checkRes(NotchM, NotchC,entry,"Notch");
    }
    return 0;
}
